home *** CD-ROM | disk | FTP | other *** search
/ Gigantic Games 2 / Gigantic Games 2.iso / pc / _a_ / attacks / sources / thinker.mod < prev    next >
Text File  |  1994-12-23  |  39KB  |  972 lines

  1. IMPLEMENTATION MODULE thinker;
  2.  
  3. (*$R-V-*)        (* Range checking OFF, overflow checking OFF *)
  4.  
  5. (*   This module handles all the routines necessary for the computer to   *)
  6. (* to play.  It also has some routines that are convenient for checking   *)
  7. (* to see if the human player screwed up or not.                          *)
  8.  
  9. FROM attacksgraphics
  10.   IMPORT   ChangePointer, DrawSquare, mywindowptr;
  11. FROM header
  12.   IMPORT   state, movetype, boardrange, boardtype, playertype, squaretype,
  13.            allmovestype, difficulty, pointercode, gameover, currentpointer,
  14.            backedup, maxmovetypemoves;
  15. FROM mdgenerallib
  16.   IMPORT   RealRandom, MyPause;
  17. FROM Intuition
  18.   IMPORT   IDCMPFlags, IntuiMessagePtr, MENUNUM, ITEMNUM;
  19. FROM Ports
  20.   IMPORT   GetMsg, ReplyMsg;
  21. FROM RandomNumbers
  22.   IMPORT   Random;
  23. FROM TermInOut
  24.   IMPORT   WriteString, WriteLn, WriteCard, WriteInt;
  25.  
  26.  
  27. CONST
  28.   winnumber  =  100;            (* This is number returned for a WIN.  *)
  29.   losenumber = -100;            (* This one's for a LOSE.              *)
  30.   ranpick = 0.1;                (* This tells how smart it is for diff *)
  31.                                 (*  level 2.                           *)
  32.   maxmoves = 400;               (* The maximun number of moves genera- *)
  33.                                 (*  ted per level.                     *)
  34.   numwhich = 5;                 (* Tells how many guesses the computer *)
  35.                                 (*  gets when doing difficulty 2.      *)
  36.  
  37. VAR
  38.   interrupt : BOOLEAN;          (* When this is TRUE, then the compu-  *)
  39.                                 (*  ter's move is to be aborted.       *)
  40.   imessageptr : IntuiMessagePtr;   (* Points to an intuimessage     *)
  41.  
  42. (************************************************************************)
  43. PROCEDURE OtherPlayer (player : playertype) : playertype;
  44.  
  45. (*   Simply returns the other player     *)
  46. BEGIN
  47.   IF player = red THEN
  48.      RETURN blue;
  49.      END;
  50.   RETURN red;
  51. END OtherPlayer;
  52.  
  53. (************************************************************************)
  54. PROCEDURE LegalMove (move : movetype) : BOOLEAN;
  55.  
  56. (*   This simply checks to see if the given move is a valid move, con- *)
  57. (* sidering the current state of the game.  It is NOT assumed that     *)
  58. (* the initial component of the move is valid.  It does NOT assume     *)
  59. (* both of the move components are valid locations.  But it does as-   *)
  60. (* sume that the board has been properly initialized so that the outer *)
  61. (* edges are blocks.  It operates using the global variable, state.    *)
  62.  
  63. VAR
  64.   legal : BOOLEAN;
  65.   checkx, checky : boardrange;     (* used to see if moves are in range *)
  66.  
  67. BEGIN
  68.   legal := FALSE;
  69.   IF (state.board[move.fromX, move.fromY] = state.turn) AND
  70.      (state.board[move.toX,move.toY] = empty) THEN
  71.      IF move.toX > move.fromX THEN
  72.         checkx := move.toX - move.fromX;
  73.         ELSE checkx := move.fromX - move.toX;
  74.         END;
  75.      IF move.toY > move.fromY THEN
  76.         checky := move.toY - move.fromY;
  77.         ELSE checky := move.fromY - move.toY;
  78.         END;
  79.      IF (checkx < 3) AND (checky < 3) THEN
  80.         legal := TRUE;
  81.         END;
  82.      END;
  83.  
  84.   RETURN legal;
  85. END LegalMove;
  86.  
  87.  
  88. (**************************************************************************)
  89. PROCEDURE FindAllMoves (VAR board : boardtype; player : playertype;
  90.                         VAR moves : allmovestype);
  91.  
  92. (*   This procedure finds all the possible moves for player in the posi-  *)
  93. (* tion of the given board.  The resultant moves are stored in the vari-  *)
  94. (* able, moves.  If there are no moves possible, then moves.nummoves = 0. *)
  95. (*                                                                        *)
  96. (*   INPUT                                                                *)
  97. (*            board                Of boardtype.  It describes the state  *)
  98. (*                                 of the board in question.              *)
  99. (*                                                                        *)
  100. (*            player               This tells which side (player) this    *)
  101. (*                                 procedure checks the moves for.        *)
  102. (*                                                                        *)
  103. (*   OUTPUT                                                               *)
  104. (*            moves                The data structure that holds all the  *)
  105. (*                                 moves.                                 *)
  106. VAR
  107.   i, j : boardrange;
  108.  
  109. BEGIN
  110.   moves.nummoves := 0;
  111.   FOR i := 1 TO 7 DO   FOR j := 1 TO 7 DO
  112.      IF board[i,j] = player THEN
  113.         IF (moves.nummoves < maxmoves) AND (board[i-2,j-2] = empty) THEN
  114.            IF moves.nummoves = maxmovetypemoves THEN
  115.               RETURN;
  116.               END;
  117.            INC(moves.nummoves);
  118.            moves.moves[moves.nummoves].fromX := i;
  119.            moves.moves[moves.nummoves].fromY := j;
  120.            moves.moves[moves.nummoves].toX := i - 2;
  121.            moves.moves[moves.nummoves].toY := j - 2;
  122.            END;
  123.         IF (moves.nummoves < maxmoves) AND (board[i-2,j-1] = empty) THEN
  124.            IF moves.nummoves = maxmovetypemoves THEN
  125.               RETURN;
  126.               END;
  127.            INC(moves.nummoves);
  128.            moves.moves[moves.nummoves].fromX := i;
  129.            moves.moves[moves.nummoves].fromY := j;
  130.            moves.moves[moves.nummoves].toX := i - 2;
  131.            moves.moves[moves.nummoves].toY := j - 1;
  132.            END;
  133.         IF (moves.nummoves < maxmoves) AND (board[i-2,j] = empty) THEN
  134.            IF moves.nummoves = maxmovetypemoves THEN
  135.               RETURN;
  136.               END;
  137.            INC(moves.nummoves);
  138.            moves.moves[moves.nummoves].fromX := i;
  139.            moves.moves[moves.nummoves].fromY := j;
  140.            moves.moves[moves.nummoves].toX := i - 2;
  141.            moves.moves[moves.nummoves].toY := j;
  142.            END;
  143.         IF (moves.nummoves < maxmoves) AND (board[i-2,j+1] = empty) THEN
  144.            IF moves.nummoves = maxmovetypemoves THEN
  145.               RETURN;
  146.               END;
  147.            INC(moves.nummoves);
  148.            moves.moves[moves.nummoves].fromX := i;
  149.            moves.moves[moves.nummoves].fromY := j;
  150.            moves.moves[moves.nummoves].toX := i - 2;
  151.            moves.moves[moves.nummoves].toY := j + 1;
  152.            END;
  153.         IF (moves.nummoves < maxmoves) AND (board[i-2,j+2] = empty) THEN
  154.            IF moves.nummoves = maxmovetypemoves THEN
  155.               RETURN;
  156.               END;
  157.            INC(moves.nummoves);
  158.            moves.moves[moves.nummoves].fromX := i;
  159.            moves.moves[moves.nummoves].fromY := j;
  160.            moves.moves[moves.nummoves].toX := i - 2;
  161.            moves.moves[moves.nummoves].toY := j + 2;
  162.            END;
  163.         IF (moves.nummoves < maxmoves) AND (board[i-1,j-2] = empty) THEN
  164.            IF moves.nummoves = maxmovetypemoves THEN
  165.               RETURN;
  166.               END;
  167.            INC(moves.nummoves);
  168.            moves.moves[moves.nummoves].fromX := i;
  169.            moves.moves[moves.nummoves].fromY := j;
  170.            moves.moves[moves.nummoves].toX := i - 1;
  171.            moves.moves[moves.nummoves].toY := j - 2;
  172.            END;
  173.         IF (moves.nummoves < maxmoves) AND (board[i-1,j-1] = empty) THEN
  174.            IF moves.nummoves = maxmovetypemoves THEN
  175.               RETURN;
  176.               END;
  177.            INC(moves.nummoves);
  178.            moves.moves[moves.nummoves].fromX := i;
  179.            moves.moves[moves.nummoves].fromY := j;
  180.            moves.moves[moves.nummoves].toX := i - 1;
  181.            moves.moves[moves.nummoves].toY := j - 1;
  182.            END;
  183.         IF (moves.nummoves < maxmoves) AND (board[i-1,j] = empty) THEN
  184.            IF moves.nummoves = maxmovetypemoves THEN
  185.               RETURN;
  186.               END;
  187.            INC(moves.nummoves);
  188.            moves.moves[moves.nummoves].fromX := i;
  189.            moves.moves[moves.nummoves].fromY := j;
  190.            moves.moves[moves.nummoves].toX := i - 1;
  191.            moves.moves[moves.nummoves].toY := j;
  192.            END;
  193.         IF (moves.nummoves < maxmoves) AND (board[i-1,j+1] = empty) THEN
  194.            IF moves.nummoves = maxmovetypemoves THEN
  195.               RETURN;
  196.               END;
  197.            INC(moves.nummoves);
  198.            moves.moves[moves.nummoves].fromX := i;
  199.            moves.moves[moves.nummoves].fromY := j;
  200.            moves.moves[moves.nummoves].toX := i - 1;
  201.            moves.moves[moves.nummoves].toY := j + 1;
  202.            END;
  203.         IF (moves.nummoves < maxmoves) AND (board[i-1,j+2] = empty) THEN
  204.            IF moves.nummoves = maxmovetypemoves THEN
  205.               RETURN;
  206.               END;
  207.            INC(moves.nummoves);
  208.            moves.moves[moves.nummoves].fromX := i;
  209.            moves.moves[moves.nummoves].fromY := j;
  210.            moves.moves[moves.nummoves].toX := i - 1;
  211.            moves.moves[moves.nummoves].toY := j + 2;
  212.            END;
  213.         IF (moves.nummoves < maxmoves) AND (board[i,j-2] = empty) THEN
  214.            IF moves.nummoves = maxmovetypemoves THEN
  215.               RETURN;
  216.               END;
  217.            INC(moves.nummoves);
  218.            moves.moves[moves.nummoves].fromX := i;
  219.            moves.moves[moves.nummoves].fromY := j;
  220.            moves.moves[moves.nummoves].toX := i;
  221.            moves.moves[moves.nummoves].toY := j - 2;
  222.            END;
  223.         IF (moves.nummoves < maxmoves) AND (board[i,j-1] = empty) THEN
  224.            IF moves.nummoves = maxmovetypemoves THEN
  225.               RETURN;
  226.               END;
  227.            INC(moves.nummoves);
  228.            moves.moves[moves.nummoves].fromX := i;
  229.            moves.moves[moves.nummoves].fromY := j;
  230.            moves.moves[moves.nummoves].toX := i;
  231.            moves.moves[moves.nummoves].toY := j - 1;
  232.            END;
  233.         IF (moves.nummoves < maxmoves) AND (board[i,j+1] = empty) THEN
  234.            IF moves.nummoves = maxmovetypemoves THEN
  235.               RETURN;
  236.               END;
  237.            INC(moves.nummoves);
  238.            moves.moves[moves.nummoves].fromX := i;
  239.            moves.moves[moves.nummoves].fromY := j;
  240.            moves.moves[moves.nummoves].toX := i;
  241.            moves.moves[moves.nummoves].toY := j + 1;
  242.            END;
  243.         IF (moves.nummoves < maxmoves) AND (board[i,j+2] = empty) THEN
  244.            IF moves.nummoves = maxmovetypemoves THEN
  245.               RETURN;
  246.               END;
  247.            INC(moves.nummoves);
  248.            moves.moves[moves.nummoves].fromX := i;
  249.            moves.moves[moves.nummoves].fromY := j;
  250.            moves.moves[moves.nummoves].toX := i;
  251.            moves.moves[moves.nummoves].toY := j + 2;
  252.            END;
  253.         IF (moves.nummoves < maxmoves) AND (board[i+1,j-2] = empty) THEN
  254.            IF moves.nummoves = maxmovetypemoves THEN
  255.               RETURN;
  256.               END;
  257.            INC(moves.nummoves);
  258.            moves.moves[moves.nummoves].fromX := i;
  259.            moves.moves[moves.nummoves].fromY := j;
  260.            moves.moves[moves.nummoves].toX := i + 1;
  261.            moves.moves[moves.nummoves].toY := j - 2;
  262.            END;
  263.         IF (moves.nummoves < maxmoves) AND (board[i+1,j-1] = empty) THEN
  264.            IF moves.nummoves = maxmovetypemoves THEN
  265.               RETURN;
  266.               END;
  267.            INC(moves.nummoves);
  268.            moves.moves[moves.nummoves].fromX := i;
  269.            moves.moves[moves.nummoves].fromY := j;
  270.            moves.moves[moves.nummoves].toX := i + 1;
  271.            moves.moves[moves.nummoves].toY := j - 1;
  272.            END;
  273.         IF (moves.nummoves < maxmoves) AND (board[i+1,j] = empty) THEN
  274.            IF moves.nummoves = maxmovetypemoves THEN
  275.               RETURN;
  276.               END;
  277.            INC(moves.nummoves);
  278.            moves.moves[moves.nummoves].fromX := i;
  279.            moves.moves[moves.nummoves].fromY := j;
  280.            moves.moves[moves.nummoves].toX := i + 1;
  281.            moves.moves[moves.nummoves].toY := j;
  282.            END;
  283.         IF (moves.nummoves < maxmoves) AND (board[i+1,j+1] = empty) THEN
  284.            IF moves.nummoves = maxmovetypemoves THEN
  285.               RETURN;
  286.               END;
  287.            INC(moves.nummoves);
  288.            moves.moves[moves.nummoves].fromX := i;
  289.            moves.moves[moves.nummoves].fromY := j;
  290.            moves.moves[moves.nummoves].toX := i + 1;
  291.            moves.moves[moves.nummoves].toY := j + 1;
  292.            END;
  293.         IF (moves.nummoves < maxmoves) AND (board[i+1,j+2] = empty) THEN
  294.            IF moves.nummoves = maxmovetypemoves THEN
  295.               RETURN;
  296.               END;
  297.            INC(moves.nummoves);
  298.            moves.moves[moves.nummoves].fromX := i;
  299.            moves.moves[moves.nummoves].fromY := j;
  300.            moves.moves[moves.nummoves].toX := i + 1;
  301.            moves.moves[moves.nummoves].toY := j + 2;
  302.            END;
  303.         IF (moves.nummoves < maxmoves) AND (board[i+2,j-2] = empty) THEN
  304.            IF moves.nummoves = maxmovetypemoves THEN
  305.               RETURN;
  306.               END;
  307.            INC(moves.nummoves);
  308.            moves.moves[moves.nummoves].fromX := i;
  309.            moves.moves[moves.nummoves].fromY := j;
  310.            moves.moves[moves.nummoves].toX := i + 2;
  311.            moves.moves[moves.nummoves].toY := j - 2;
  312.            END;
  313.         IF (moves.nummoves < maxmoves) AND (board[i+2,j-1] = empty) THEN
  314.            IF moves.nummoves = maxmovetypemoves THEN
  315.               RETURN;
  316.               END;
  317.            INC(moves.nummoves);
  318.            moves.moves[moves.nummoves].fromX := i;
  319.            moves.moves[moves.nummoves].fromY := j;
  320.            moves.moves[moves.nummoves].toX := i + 2;
  321.            moves.moves[moves.nummoves].toY := j - 1;
  322.            END;
  323.         IF (moves.nummoves < maxmoves) AND (board[i+2,j] = empty) THEN
  324.            IF moves.nummoves = maxmovetypemoves THEN
  325.               RETURN;
  326.               END;
  327.            INC(moves.nummoves);
  328.            moves.moves[moves.nummoves].fromX := i;
  329.            moves.moves[moves.nummoves].fromY := j;
  330.            moves.moves[moves.nummoves].toX := i + 2;
  331.            moves.moves[moves.nummoves].toY := j;
  332.            END;
  333.         IF (moves.nummoves < maxmoves) AND (board[i+2,j+1] = empty) THEN
  334.            IF moves.nummoves = maxmovetypemoves THEN
  335.               RETURN;
  336.               END;
  337.            INC(moves.nummoves);
  338.            moves.moves[moves.nummoves].fromX := i;
  339.            moves.moves[moves.nummoves].fromY := j;
  340.            moves.moves[moves.nummoves].toX := i + 2;
  341.            moves.moves[moves.nummoves].toY := j + 1;
  342.            END;
  343.         IF (moves.nummoves < maxmoves) AND (board[i+2,j+2] = empty) THEN
  344.            IF moves.nummoves = maxmovetypemoves THEN
  345.               RETURN;
  346.               END;
  347.            INC(moves.nummoves);
  348.            moves.moves[moves.nummoves].fromX := i;
  349.            moves.moves[moves.nummoves].fromY := j;
  350.            moves.moves[moves.nummoves].toX := i + 2;
  351.            moves.moves[moves.nummoves].toY := j + 2;
  352.            END;
  353.         END;
  354.      END; END;
  355. END FindAllMoves;
  356.  
  357. (********************************************************)
  358. PROCEDURE GoodMovePossible (board : boardtype; player : playertype)
  359.                             : BOOLEAN;
  360. (*   This procedure returns TRUE only if on the given board, player has   *)
  361. (* has a legal move available. It returns FALSE otherwise.                *)
  362.  
  363. VAR
  364.   good : BOOLEAN;
  365.   i,j : CARDINAL;
  366.  
  367. BEGIN
  368.   FOR i := 1 TO 7 DO
  369.     FOR j := 1 TO 7 DO
  370.       IF board[i,j] = player  THEN
  371.         IF board[i-2,j-2] = empty THEN RETURN(TRUE); END;
  372.         IF board[i-1,j-2] = empty THEN RETURN(TRUE); END;
  373.         IF board[i,j-2] = empty THEN RETURN(TRUE); END;
  374.         IF board[i+1,j-2] = empty THEN RETURN(TRUE); END;
  375.         IF board[i+2,j-2] = empty THEN RETURN(TRUE); END;
  376.         IF board[i-2,j-1] = empty THEN RETURN(TRUE); END;
  377.         IF board[i-1,j-1] = empty THEN RETURN(TRUE); END;
  378.         IF board[i,j-1] = empty THEN RETURN(TRUE); END;
  379.         IF board[i+1,j-1] = empty THEN RETURN(TRUE); END;
  380.         IF board[i+2,j-1] = empty THEN RETURN(TRUE); END;
  381.         IF board[i-2,j] = empty THEN RETURN(TRUE); END;
  382.         IF board[i-1,j] = empty THEN RETURN(TRUE); END;
  383.         IF board[i+1,j] = empty THEN RETURN(TRUE); END;
  384.         IF board[i+2,j] = empty THEN RETURN(TRUE); END;
  385.         IF board[i-2,j+1] = empty THEN RETURN(TRUE); END;
  386.         IF board[i-1,j+1] = empty THEN RETURN(TRUE); END;
  387.         IF board[i,j+1] = empty THEN RETURN(TRUE); END;
  388.         IF board[i+1,j+1] = empty THEN RETURN(TRUE); END;
  389.         IF board[i+2,j+1] = empty THEN RETURN(TRUE); END;
  390.         IF board[i-2,j+2] = empty THEN RETURN(TRUE); END;
  391.         IF board[i-1,j+2] = empty THEN RETURN(TRUE); END;
  392.         IF board[i,j+2] = empty THEN RETURN(TRUE); END;
  393.         IF board[i+1,j+2] = empty THEN RETURN(TRUE); END;
  394.         IF board[i+2,j+2] = empty THEN RETURN(TRUE); END;
  395.         END; (* main if *)
  396.       END;  (* for j *)
  397.     END; (* for i *)
  398.   RETURN FALSE;       (* if it made it this far, then there's no moves *)
  399. END GoodMovePossible;
  400.  
  401.  
  402. (**************************************************************************)
  403. PROCEDURE GetAMove (VAR amove : movetype;  VAR moves : allmovestype)
  404.                     : BOOLEAN;
  405.  
  406. (*   The variable, amove, will be changed to hold one of the moves held   *)
  407. (* in moves.  If there are no moves, then the function will return FALSE. *)
  408. (*                                                                        *)
  409. (*   INPUT                                                                *)
  410. (*            moves             A variable of allmovestype.  It holds a   *)
  411. (*                              list of all the possible moves.           *)
  412. (*                                                                        *)
  413. (*   OUTPUT                                                               *)
  414. (*            amove             Of movetype.  This is simply one of the   *)
  415. (*                              moves held in moves.                      *)
  416. (*                                                                        *)
  417. (*            moves             Will be changed to reflect the removal of *)
  418. (*                              the move from this data structure.        *)
  419. (*                                                                        *)
  420. (*            This function returns TRUE normally.  When moves holds no   *)
  421. (*            moves (ie, moves.nummoves = 0) then this returns FALSE.     *)
  422. (*            The variable amove will then be unchanged.                  *)
  423.  
  424. BEGIN
  425.   IF moves.nummoves = 0 THEN
  426.      RETURN FALSE;
  427.      END;
  428.   amove := moves.moves[moves.nummoves];
  429.   DEC(moves.nummoves);
  430.   RETURN TRUE;
  431. END GetAMove;
  432.  
  433.  
  434. (**************************************************************************)
  435. PROCEDURE MakeNewBoard (oldboard : boardtype;  VAR newboard : boardtype;
  436.                         move : movetype;  player : playertype);
  437.  
  438. (*   This procedure makes the newboard that results from the application  *)
  439. (* of the given move.  There is no error checking here.  It is assumed    *)
  440. (* that the move is legal.  The player is the person who is moving.       *)
  441. (*                                                                        *)
  442. (*   INPUT                                                                *)
  443. (*            oldboard          A variable of boardtype.  This is the     *)
  444. (*                              state before the move is made.            *)
  445. (*                                                                        *)
  446. (*            move              This describes the move to be made in     *)
  447. (*                              movetype notation.                        *)
  448. (*                                                                        *)
  449. (*            player            The player who is making the move.        *)
  450. (*                                                                        *)
  451. (*   OUTPUT                                                               *)
  452. (*            newboard          The board that is the result of the move. *)
  453.  
  454. VAR
  455.   other : playertype;
  456.  
  457. BEGIN
  458.   newboard := oldboard;
  459.   other := OtherPlayer(player);
  460.  
  461.   newboard[move.toX,move.toY] := player;    (* add the new square *)
  462.  
  463.            (*** check to see if old square should be erased ***)
  464.   IF (move.fromX > move.toX) AND (move.fromX-2 = move.toX) OR
  465.      (move.fromX < move.toX) AND (move.fromX+2 = move.toX) OR
  466.      (move.fromY < move.toY) AND (move.fromY+2 = move.toY) OR
  467.      (move.fromY > move.toY) AND (move.fromY-2 = move.toY) THEN
  468.      newboard[move.fromX, move.fromY] := empty;
  469.      END;
  470.  
  471.   IF oldboard[move.toX-1, move.toY-1] = other THEN
  472.      newboard[move.toX-1, move.toY-1] := player;
  473.      END;
  474.   IF oldboard[move.toX-1, move.toY] = other THEN
  475.      newboard[move.toX-1, move.toY] := player;
  476.      END;
  477.   IF oldboard[move.toX-1, move.toY+1] = other THEN
  478.      newboard[move.toX-1, move.toY+1] := player;
  479.      END;
  480.   IF oldboard[move.toX, move.toY-1] = other THEN
  481.      newboard[move.toX, move.toY-1] := player;
  482.      END;
  483.   IF oldboard[move.toX, move.toY+1] = other THEN
  484.      newboard[move.toX, move.toY+1] := player;
  485.      END;
  486.   IF oldboard[move.toX+1, move.toY-1] = other THEN
  487.      newboard[move.toX+1, move.toY-1] := player;
  488.      END;
  489.   IF oldboard[move.toX+1, move.toY] = other THEN
  490.      newboard[move.toX+1, move.toY] := player;
  491.      END;
  492.   IF oldboard[move.toX+1, move.toY+1] = other THEN
  493.      newboard[move.toX+1, move.toY+1] := player;
  494.      END;
  495. END MakeNewBoard;
  496.  
  497.  
  498. (**************************************************************************)
  499. PROCEDURE CountScore (board : boardtype; player : playertype)
  500.                        : INTEGER;
  501.  
  502. (*   Given a board and a player, this function returns the player's score *)
  503. (* (that is, for the computer part of the calculations).                  *)
  504. (*                                                                        *)
  505. (*   INPUT                                                                *)
  506. (*            board                This is the board that will be scanned *)
  507. (*                                 to calculate the score.                *)
  508. (*                                                                        *)
  509. (*            player               The player who's score is wanted.      *)
  510. (*                                                                        *)
  511. (*   OUTPUT                                                               *)
  512. (*            The function returns the number of player's pieces on the   *)
  513. (*            board minus the numbe of opposing pieces.                   *)
  514.  
  515. VAR
  516.   i, j : boardrange;
  517.   score : INTEGER;
  518.   otherplayer : playertype;
  519.  
  520. BEGIN
  521.   otherplayer := OtherPlayer(player);
  522.   score := 0;
  523.   FOR i := 1 TO 7 DO
  524.      FOR j := 1 TO 7 DO
  525.         IF board[i, j] = player THEN
  526.            INC(score);
  527.            ELSIF board [i, j] = otherplayer THEN
  528.               DEC(score);
  529.            END;
  530.         END;
  531.      END;
  532.   RETURN score;
  533. END CountScore;
  534.  
  535.  
  536. (************************************************************************)
  537. PROCEDURE GameOver;
  538.  
  539. (*   This is a little thing when the game is over.                     *)
  540.  
  541. BEGIN
  542.   ChangePointer (DefaultPointer);
  543.   currentpointer := DefaultPointer;
  544.   gameover := TRUE;
  545. END GameOver;
  546.  
  547.  
  548. (***********************************************************************)
  549. PROCEDURE DoMove (move : movetype) : BOOLEAN;
  550.  
  551. (*      This does the necessary changes to facilitate a move in the    *)
  552. (* game.  It involves, finding out if the piece grows or jumps, alter- *)
  553. (* ing the board to reflect this, update the history, and change the   *)
  554. (* graphics.  Lastly, don't forget to change the player's turn!  Oh    *)
  555. (* yeah, I did in fact forget.  Change the colors of all the opponents *)
  556. (* who are adjacent to the new blob!                                   *)
  557. (*      This routine returns TRUE if there's a move available.  It     *)
  558. (* will return FALSE when the game is over.                            *)
  559.  
  560. VAR
  561.   checkx, checky : boardrange;
  562.   otherplayer : playertype;
  563.  
  564. BEGIN
  565.   (* prelims *)
  566. IF state.turn = red THEN              (* find other player's color *)
  567.   otherplayer := blue;
  568.   ELSE otherplayer := red;
  569.   END;
  570.  
  571.      (** Is it a grow or a jump? **)
  572. IF move.toX > move.fromX THEN
  573.   checkx := move.toX - move.fromX;
  574.   ELSE checkx := move.fromX - move.toX;
  575.   END;
  576. IF move.toY > move.fromY THEN
  577.   checky := move.toY - move.fromY;
  578.   ELSE checky := move.fromY - move.toY;
  579.   END;
  580.  
  581. IF (checkx = 2) OR (checky = 2) THEN     (* It's a jumper! Undraw blob. *)
  582.   state.board[move.fromX, move.fromY] := empty;
  583.   DrawSquare(move.fromX, move.fromY, empty);
  584.   END;
  585.  
  586. state.board[move.toX, move.toY] := state.turn;    (* Draw new blob. *)
  587. DrawSquare (move.toX, move.toY, state.turn);
  588.  
  589.      (****************************************************)
  590.      (* checking (and changing) all the adjacent squares *)
  591.      (****************************************************)
  592.  
  593. IF (move.toX # 1) AND (move.toY # 1)
  594.   AND (state.board[move.toX - 1, move.toY - 1] = otherplayer) THEN
  595.      state.board[move.toX - 1, move.toY - 1] := state.turn;
  596.      DrawSquare(move.toX - 1, move.toY - 1, state.turn);
  597.   END;
  598. IF (move.toY # 1)
  599.   AND (state.board[move.toX, move.toY - 1] = otherplayer) THEN
  600.      state.board[move.toX, move.toY - 1] := state.turn;
  601.      DrawSquare(move.toX, move.toY - 1, state.turn);
  602.   END;
  603. IF (move.toX # 7) AND (move.toY # 1)
  604.   AND (state.board[move.toX + 1, move.toY - 1] = otherplayer) THEN
  605.      state.board[move.toX + 1, move.toY - 1] := state.turn;
  606.      DrawSquare(move.toX + 1, move.toY - 1, state.turn);
  607.   END;
  608. IF (move.toX # 7)
  609.   AND (state.board[move.toX + 1, move.toY] = otherplayer) THEN
  610.      state.board[move.toX + 1, move.toY] := state.turn;
  611.      DrawSquare(move.toX + 1, move.toY, state.turn);
  612.   END;
  613. IF (move.toX # 7) AND (move.toY # 7)
  614.   AND (state.board[move.toX + 1, move.toY + 1] = otherplayer) THEN
  615.      state.board[move.toX + 1, move.toY + 1] := state.turn;
  616.      DrawSquare(move.toX + 1, move.toY + 1, state.turn);
  617.   END;
  618. IF (move.toY # 7)
  619.   AND (state.board[move.toX, move.toY + 1] = otherplayer) THEN
  620.      state.board[move.toX, move.toY + 1] := state.turn;
  621.      DrawSquare(move.toX, move.toY + 1, state.turn);
  622.   END;
  623. IF (move.toX # 1) AND (move.toY # 7)
  624.   AND (state.board[move.toX - 1, move.toY + 1] = otherplayer) THEN
  625.      state.board[move.toX - 1, move.toY + 1] := state.turn;
  626.      DrawSquare(move.toX - 1, move.toY + 1, state.turn);
  627.   END;
  628. IF (move.toX # 1)
  629.   AND (state.board[move.toX - 1, move.toY] = otherplayer) THEN
  630.      state.board[move.toX - 1, move.toY] := state.turn;
  631.      DrawSquare(move.toX - 1, move.toY, state.turn);
  632.   END;
  633.  
  634. IF GoodMovePossible(state.board, otherplayer) = TRUE THEN
  635.   state.turn := otherplayer;      (* modifying whose turn it is *)
  636.   ELSE
  637.      IF GoodMovePossible(state.board, state.turn) = FALSE THEN
  638.      GameOver;
  639.      RETURN FALSE;
  640.      END;
  641.   END;
  642.  
  643.   RETURN TRUE;
  644. END DoMove;
  645.  
  646.  
  647. (**************************************************************************)
  648. PROCEDURE EvalMove (VAR board : boardtype;  turn : playertype;
  649.                     player : playertype;  level : CARDINAL)
  650.                     : INTEGER;
  651.  
  652. (*   This is one of the most important procedures in the program.  It     *)
  653. (* gives a rating for a given board that (hopefully) indicates the rela-  *)
  654. (* tive value of this board for the given player.  A rating of 0 is a     *)
  655. (* totally neutral rating.  Otherwise, the higher the number, the better  *)
  656. (* the board should be for the player.  It works recursively.  The rat-   *)
  657. (* ing of a board is the average of the ratings of the boards that can    *)
  658. (* be generated from the board.  At the leaves of the tree, the rating is *)
  659. (* simply how many of player's pieces there are minus its opponent's      *)
  660. (* pieces.                                                                *)
  661. (*   Change on Feb 12:  I've changed this so that the value returned is   *)
  662. (* either the HIGHEST or the LOWEST value found, depending upon which     *)
  663. (* level it is working.  This way, if it is the computer's turn to move,  *)
  664. (* it will return the maximum value for the next level.  Otherwise, if    *)
  665. (* it's the other's turn to move (in the projected game) then it will     *)
  666. (* assume that the other will make the best move, resulting in a Minimum  *)
  667. (* score for the computer.  I hope this works better than the average.    *)
  668. (*                                                                        *)
  669. (*   INPUT                                                                *)
  670. (*            board             A variable of boardtype.  This is the     *)
  671. (*                              state that we are trying to evaluate.     *)
  672. (*                                                                        *)
  673. (*            turn              Who's turn is it right now?  May or may   *)
  674. (*                              not be the player.                        *)
  675. (*                                                                        *)
  676. (*            player            The player in question that wants the     *)
  677. (*                              board evaluated.  The result is in terms  *)
  678. (*                              of this player.                           *)
  679. (*                                                                        *)
  680. (*            level             This tells how many levels deep the re-   *)
  681. (*                              cursion is going.  It is the method of    *)
  682. (*                              stopping the recursion.                   *)
  683. (*                                                                        *)
  684. (*   OUTPUT                                                               *)
  685. (*            This returns an integer representing the value of the given *)
  686. (*            board to the player.                                        *)
  687.  
  688. VAR
  689.   allmoves : allmovestype;         (* Holds all the moves from this board *)
  690.   move : movetype;
  691.   newboard : boardtype;
  692.   otherturn : playertype;
  693.   score, tempscore : INTEGER;
  694. i,j : boardrange;
  695.  
  696. BEGIN
  697. (*WriteString("Entering EvalMove\n");
  698. IF turn = red THEN
  699.   WriteString("   turn = red\n");
  700. ELSE
  701.   WriteString("   turn = blue\n");
  702.   END;
  703. IF player=red THEN
  704.   WriteString("   player = red\n");
  705. ELSE
  706.   WriteString("   player = blue\n");
  707.   END;
  708. WriteString("   level = ");WriteCard(level,1);WriteLn;
  709. WriteString("   board:\n");
  710. FOR i := 1 TO 7 DO
  711.   FOR j := 1 TO 7 DO
  712.      WriteCard(ORD(board[j,i]),3);
  713.      END;
  714.   WriteLn;
  715.   END;
  716. *)
  717.   imessageptr := GetMsg(mywindowptr^.UserPort^);  (* Did user abort? *)
  718.   IF imessageptr # NIL THEN
  719.      IF (MenuPick IN imessageptr^.Class) AND
  720.         (MENUNUM(imessageptr^.Code) = 0) AND
  721.         (ITEMNUM(imessageptr^.Code) = 0) THEN
  722.         interrupt := TRUE;
  723.         END;
  724.      ReplyMsg(imessageptr);
  725.      END;
  726.   IF interrupt THEN RETURN 0;         (* user has aborted computer move *)
  727.      END;
  728.  
  729.   IF level = 1 THEN                      (***  Base case  ***)
  730. (*WriteString("Exiting EvalMove from the base case\n");*)
  731.      RETURN CountScore(board, player);
  732.      END;
  733.  
  734.   otherturn := OtherPlayer(turn);
  735.   FindAllMoves(board, turn, allmoves);
  736.  
  737.   IF ODD(level) THEN                     (*** Set initial score  ***)
  738.      score := MIN(INTEGER);
  739.      ELSE score := MAX(INTEGER);
  740.      END;
  741.  
  742.   IF allmoves.nummoves = 0 THEN          (***  No moves for turn  ***)
  743.      FindAllMoves(board, otherturn, allmoves);
  744.      IF allmoves.nummoves = 0 THEN
  745.         IF player = turn THEN
  746.            RETURN losenumber;
  747.         ELSE
  748.            RETURN winnumber;
  749.            END;
  750.         END;
  751.      IF player = turn THEN
  752.         RETURN losenumber DIV 2;
  753.      ELSE
  754.         RETURN winnumber DIV 2;
  755.         END;
  756.      END;
  757.  
  758.   WHILE GetAMove(move, allmoves) DO      (*** Normal operation ***)
  759.      MakeNewBoard(board, newboard, move, turn);
  760.      tempscore := EvalMove(newboard, otherturn, player, level - 1);
  761. (*WriteString("   tempscore = ");WriteInt(tempscore,1);WriteLn;*)
  762.      IF interrupt THEN RETURN 0;         (* just checking *)
  763.         END;
  764.  
  765.      IF ODD(level) THEN                  (* Odd level, MAXIMIZE *)
  766.         IF tempscore > score THEN
  767.            score := tempscore;
  768.            END;
  769.         ELSE
  770.            IF tempscore < score THEN
  771.               score := tempscore;
  772.               END;
  773.         END;
  774. (*WriteString("   score = ");WriteInt(score,1);WriteLn;*)
  775.      END;
  776. (*WriteString("Exiting EvalMove after WHILE loop and return score\n");*)
  777.   RETURN score;
  778.  
  779. END EvalMove;
  780.  
  781.  
  782. (**************************************************************************)
  783. PROCEDURE DoComputerMove() : BOOLEAN;
  784.  
  785. (*   This is the computer equivalent of the procedure, DoMove.  It exe-   *)
  786. (* cutes a computer's move, assuming that the computer already has a le-  *)
  787. (* gitate move possible.  It utilizes the global variable, state.  Also   *)
  788. (* note that this assumes that the current turn is the computer's turn.   *)
  789. (* It's up to the caller to make sure that it is indeed time to play the  *)
  790. (* computer.                                                              *)
  791. (*                                                                        *)
  792. (*   INPUT                                                                *)
  793. (*            n/a                                                         *)
  794. (*                                                                        *)
  795. (*   OUTPUT                                                               *)
  796. (*            The state and the screen will be changed to reflect the     *)
  797. (*            move execute by the computer.                               *)
  798.  
  799. VAR
  800.   movevalues : ARRAY[1..maxmoves] OF INTEGER;  (* holds the moves' values *)
  801.   movelist : allmovestype;                  (* holds the moves themselves *)
  802.   amove : movetype;
  803.   newboard : boardtype;
  804.   otherplayer : playertype;
  805.   better : BOOLEAN;
  806.   noother : BOOLEAN;
  807.   i, j, counter,
  808.   searchdepth,                     (* how deep do we search?              *)
  809.   which : CARDINAL;                (* Tells which move has been selected. *)
  810.   whicharray : ARRAY[1..numwhich]  (* Holds the moves for the one that    *)
  811.            OF CARDINAL;            (*  picks a good move at random.       *)
  812.   currentvalue : INTEGER;          (* What's the best value seen so far?  *)
  813.   currentvalarray : ARRAY [1..numwhich]  (* Similar to whicharray   *)
  814.            OF INTEGER;
  815.  
  816. BEGIN
  817.   interrupt := FALSE;
  818.  
  819.   imessageptr := GetMsg(mywindowptr^.UserPort^);  (* Did user abort? *)
  820.   IF imessageptr # NIL THEN
  821.      IF (MenuPick IN imessageptr^.Class) AND
  822.         (MENUNUM(imessageptr^.Code) = 0) AND
  823.         (ITEMNUM(imessageptr^.Code) = 0) THEN
  824.         interrupt := TRUE;
  825.         END;
  826.      ReplyMsg(imessageptr);
  827.      END;
  828.   IF interrupt THEN
  829.      backedup := TRUE;
  830.      RETURN TRUE;
  831.      END;
  832.  
  833.   IF difficulty < 3 THEN        (* Finding the search depth. *)
  834.      searchdepth := 1;
  835.      ELSE searchdepth := difficulty - 2;
  836.      END;
  837.  
  838.   otherplayer := OtherPlayer(state.turn);
  839.  
  840.   noother := TRUE;                         (* To speed things up at end *)
  841.   FOR i := 1 TO 7 DO   FOR j := 1 TO 7 DO
  842.      IF state.board[i,j] = otherplayer THEN
  843.         noother := FALSE;
  844.         i := 7; j := 7;
  845.         END;
  846.      END; END;
  847.   IF noother THEN
  848.      searchdepth := 1;
  849.      END;
  850.  
  851.   FindAllMoves (state.board, state.turn, movelist);
  852.  
  853.   imessageptr := GetMsg(mywindowptr^.UserPort^);  (* Did user abort? *)
  854.   IF imessageptr # NIL THEN
  855.      IF (MenuPick IN imessageptr^.Class) AND
  856.         (MENUNUM(imessageptr^.Code) = 0) AND
  857.         (ITEMNUM(imessageptr^.Code) = 0) THEN
  858.         interrupt := TRUE;
  859.         END;
  860.      ReplyMsg(imessageptr);
  861.      END;
  862.   IF interrupt THEN
  863.      backedup := TRUE;
  864.      RETURN TRUE;
  865.      END;
  866.  
  867.   IF difficulty = 1 THEN        (* Tells to pick a move at random! *)
  868.      which := CARDINAL(Random(LONGCARD(movelist.nummoves))) + 1;
  869.      RETURN DoMove(movelist.moves[which]);
  870.      END;
  871.  
  872.   counter := movelist.nummoves;
  873.  
  874.               (*****************************************)
  875.               (* Find all the values for all the moves *)
  876.               (*****************************************)
  877.   WHILE counter > 0 DO
  878.      MakeNewBoard(state.board, newboard, movelist.moves[counter], state.turn);
  879.      movevalues[counter] :=
  880.              EvalMove(newboard, otherplayer, state.turn, searchdepth);
  881.  
  882.      imessageptr := GetMsg(mywindowptr^.UserPort^);  (* Did user abort? *)
  883.      IF imessageptr # NIL THEN
  884.         IF (MenuPick IN imessageptr^.Class) AND
  885.            (MENUNUM(imessageptr^.Code) = 0) AND
  886.            (ITEMNUM(imessageptr^.Code) = 0) THEN
  887.            interrupt := TRUE;
  888.            END;
  889.         ReplyMsg(imessageptr);
  890.         END;
  891.  
  892.      IF interrupt THEN
  893.         backedup := TRUE;
  894.         RETURN TRUE;
  895.         END;
  896.  
  897.      DEC(counter);
  898.      END;
  899.               (***********************)
  900.               (* Deciding what to do *)
  901.               (***********************)
  902.   CASE difficulty OF
  903.  
  904.      0  :                 (* The computer TRIES to lose! *)
  905.         currentvalue := MAX(INTEGER);
  906.         FOR i := 1 TO movelist.nummoves DO
  907.            IF movevalues[i] < currentvalue THEN
  908.               which := i;
  909.               currentvalue := movevalues[i];
  910.               END;
  911.            END;
  912.            |
  913.      2  :                 (* Takes one of the best numwhich moves *)
  914.         IF movelist.nummoves <= numwhich THEN
  915.            which := CARDINAL(Random(LONGCARD(movelist.nummoves))) + 1;
  916.         ELSE
  917.            FOR i := 1 TO numwhich DO     (* Set up the array *)
  918.               j := CARDINAL(Random(LONGCARD(numwhich))) + 1;
  919.               whicharray[i] := j;
  920.               currentvalarray[i] := movevalues[j];
  921.               END;
  922.  
  923.            FOR i := 1 TO movelist.nummoves DO  (* find the numwhich vals *)
  924.               better := FALSE;
  925.               j := 1;
  926.               WHILE (NOT better) AND (j <= numwhich) DO
  927.                  IF movevalues[i] > currentvalarray[j] THEN
  928.                     better := TRUE;
  929.                     whicharray[j] := i;
  930.                     currentvalarray[j] := movevalues[i];
  931.                     ELSE INC(j);
  932.                     END;
  933.                  END;  (* while *)
  934.               END;  (* for i *)
  935.            i := CARDINAL(Random(LONGCARD(numwhich))) + 1;
  936.            which := whicharray[i];
  937.         END;  (* if movelist.nummoves *)
  938.            |
  939.  
  940.      ELSE
  941.         currentvalue := MIN(INTEGER);
  942.         FOR i := 1 TO movelist.nummoves DO
  943.            IF movevalues[i] > currentvalue THEN
  944.               which := i;
  945.               currentvalue := movevalues[i];
  946.               END;
  947.            END;
  948.      END;
  949.  
  950.   imessageptr := GetMsg(mywindowptr^.UserPort^);  (* Did user abort? *)
  951.   IF imessageptr # NIL THEN
  952.      IF (MenuPick IN imessageptr^.Class) AND
  953.         (MENUNUM(imessageptr^.Code) = 0) AND
  954.         (ITEMNUM(imessageptr^.Code) = 0) THEN
  955.         interrupt := TRUE;
  956.         END;
  957.      ReplyMsg(imessageptr);
  958.      END;
  959.   IF interrupt THEN
  960.      backedup := TRUE;
  961.      RETURN TRUE;
  962.      END;
  963.  
  964.   RETURN DoMove(movelist.moves[which]);
  965.  
  966. END DoComputerMove;
  967.  
  968.  
  969. (******************************************************)
  970.  
  971. END thinker.
  972.